#ifndef _DRIVE_H_
#define _DRIVE_H_

#include <stdint.h>

namespace SEngine
{
    enum GraphicsEnum 
    {
        NEVER = 0x0200,
        LESS = 0x0201,
        EQUAL = 0x0202,
        LEQUAL = 0x0203,
        GREATER = 0x0204,
        NOTEQUAL = 0x0205,
        GEQUAL = 0x0206,
        ALWAYS = 0x0207,
        KEEP = 0x1E00,
        REPLACE = 0x1E01,
        STENCIL_TEST = 0x0B90,
        DEPTH_TEST = 0x0B71,
        FRAMEBUFFER_SRGB = 0x8DB9,

    };

    enum GraphicsFace
    {
        FRONT_LEFT          = 0x0400,
        FRONT_RIGHT         = 0x0401,
        BACK_LEFT           = 0x0402,
        BACK_RIGHT          = 0x0403,
        FRONT               = 0x0404,
        BACK                = 0x0405,
        LEFT                = 0x0406,
        RIGHT               = 0x0407,
        FRONT_AND_BACK      = 0x0408,
    };

    enum GraphicsFaceMode
    {
        POINT   = 0x1B00,
        LINE    = 0x1B01,
        FILL    = 0x1B02,
    };

    enum GraphicsAPI
    {
        None = 0,
        OpenGL
    };

    enum BufferType 
    {
        DEPTH_BUFFER_BIT    = 0x00000100,
        STENCIL_BUFFER_BIT  = 0x00000400,
        COLOR_BUFFER_BIT    = 0x00004000,
    };

    enum ElemMode 
    {
        POINTS = 0x0000,
        LINES = 0x0001,
        LINE_LOOP = 0x0002,
        LINE_STRIP = 0x0003,
        TRIANGLES = 0x0004,
        TRIANGLE_STRIP = 0x0005,
        TRIANGLE_FAN = 0x0006,
    };

    enum ElemType {
        BYTE = 0x1400,
        UNSIGNED_BYTE = 0x1401,
        SHORT = 0x1402,
        UNSIGNED_SHORT = 0x1403,
        INT = 0x1404,
        UNSIGNED_INT = 0x1405,
        FLOAT = 0x1406,
    };

    enum ElemBufferType {
        ARRAY_BUFFER = 0x8892,
        ELEMENT_ARRAY_BUFFER = 0x8893,
        UNIFORM_BUFFER = 0x8A11,
    };

    enum UsageType {
        STREAM_DRAW = 0x88E0,
        STREAM_READ = 0x88E1,
        STREAM_COPY = 0x88E2,
        STATIC_DRAW = 0x88E4,
        STATIC_READ = 0x88E5,
        STATIC_COPY = 0x88E6,
        DYNAMIC_DRAW = 0x88E8,
        DYNAMIC_READ = 0x88E9,
        DYNAMIC_COPY = 0x88EA,
    };

    enum ColorFormat
    {
        COLOR = 0x1800,
        DEPTH = 0x1801,
        STENCIL = 0x1802,
        STENCIL_INDEX = 0x1901,
        DEPTH_COMPONENT = 0x1902,
        RED = 0x1903,
        GREEN = 0x1904,
        BLUE = 0x1905,
        ALPHA = 0x1906,
        RGB = 0x1907,
        RGBA = 0x1908,
        RGBA32F = 0x8814,
        RGB32F = 0x8815,
        RGBA16F = 0x881A,
        RGB16F = 0x881B,
    };

    enum Attachment
    {
        COLOR_ATTACHMENT0 = 0x8CE0,
        COLOR_ATTACHMENT1 = 0x8CE1,
        COLOR_ATTACHMENT2 = 0x8CE2,
        COLOR_ATTACHMENT3 = 0x8CE3,
        COLOR_ATTACHMENT4 = 0x8CE4,
        COLOR_ATTACHMENT5 = 0x8CE5,
        COLOR_ATTACHMENT6 = 0x8CE6,
        COLOR_ATTACHMENT7 = 0x8CE7,
        COLOR_ATTACHMENT8 = 0x8CE8,
        COLOR_ATTACHMENT9 = 0x8CE9,
        COLOR_ATTACHMENT10 = 0x8CEA,
        COLOR_ATTACHMENT11 = 0x8CEB,
        COLOR_ATTACHMENT12 = 0x8CEC,
        COLOR_ATTACHMENT13 = 0x8CED,
        COLOR_ATTACHMENT14 = 0x8CEE,
        COLOR_ATTACHMENT15 = 0x8CEF,
        COLOR_ATTACHMENT16 = 0x8CF0,
        COLOR_ATTACHMENT17 = 0x8CF1,
        COLOR_ATTACHMENT18 = 0x8CF2,
        COLOR_ATTACHMENT19 = 0x8CF3,
        COLOR_ATTACHMENT20 = 0x8CF4,
        COLOR_ATTACHMENT21 = 0x8CF5,
        COLOR_ATTACHMENT22 = 0x8CF6,
        COLOR_ATTACHMENT23 = 0x8CF7,
        COLOR_ATTACHMENT24 = 0x8CF8,
        COLOR_ATTACHMENT25 = 0x8CF9,
        COLOR_ATTACHMENT26 = 0x8CFA,
        COLOR_ATTACHMENT27 = 0x8CFB,
        COLOR_ATTACHMENT28 = 0x8CFC,
        COLOR_ATTACHMENT29 = 0x8CFD,
        COLOR_ATTACHMENT30 = 0x8CFE,
        COLOR_ATTACHMENT31 = 0x8CFF,
        DEPTH_ATTACHMENT = 0x8D00,
        STENCIL_ATTACHMENT = 0x8D20,
    };

    enum TextureParameterKey
    {
        TEXTURE_WRAP_S = 0x2802,
        TEXTURE_WRAP_T = 0x2803,
        TEXTURE_WRAP_R = 0x8072,
        TEXTURE_MAG_FILTER = 0x2800,
        TEXTURE_MIN_FILTER = 0x2801,
    };

    enum TextureParameterValue
    {
        CLAMP_TO_EDGE = 0x812Fc,
        NEAREST = 0x2600,
        LINEAR = 0x2601,
        REPEAT = 0x2901,
        NEAREST_MIPMAP_NEAREST = 0x2700,
        LINEAR_MIPMAP_NEAREST = 0x2701,
        NEAREST_MIPMAP_LINEAR = 0x2702,
        LINEAR_MIPMAP_LINEAR = 0x2703,
    };

    enum TextureCubeMapPositive {
        TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515,
        TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516,
        TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517,
        TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518,
        TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519,
        TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A,
    };

    struct PipeLineState
    {
        bool blend{false};
        bool cullFace{false};
        bool cullFront{false};
        bool depth{true};
    };

    class IDrive
    {
    public:
        virtual int  Load() = 0;
        virtual int  Load(void*) = 0;
        virtual void Viewport(int x, int y, int w, int h) = 0;
        virtual void Clear(int type) = 0;
        virtual void ClearColor(float r, float g, float b, float a) = 0;
        virtual void SetLineWidth(float width) = 0;
        virtual void DrawElements(ElemMode mode, int size, ElemType type, void* indices, size_t instanceCount = 1) = 0;
        virtual void DrawArrays(ElemMode mode, int first, size_t count, size_t instanceCount = 1) = 0;
        virtual void BufferData(int target, size_t size, const void * data, int usage) = 0;
        virtual void BufferSubData(int target, signed long long int offset, size_t size, const void *data) = 0;
        virtual void VertexAttribPointer(uint32_t index, int size, int type, bool normalized, int stride, const void *pointer) = 0;
        virtual void EnableVertexAttribArray(uint32_t index) = 0;
        virtual void SetPipeLineState(PipeLineState pso) = 0;
        virtual void ReadPixels(int x, int y, int width, int height, ColorFormat format, ElemType type, void *pixels) = 0;
        virtual void EnableByteAlignment(bool value) = 0;
        virtual void EnableMultiSample(bool value) = 0;
        virtual void SetPolygonMode(GraphicsFace face, GraphicsFaceMode mode) = 0;
        virtual void SetStencilFunc(GraphicsEnum en, int ref, uint32_t mask) = 0;
        virtual void SetStencilOp(GraphicsEnum sfail, GraphicsEnum dpfail, GraphicsEnum dppass) = 0;
        virtual void SetStencilMask(uint32_t mask) = 0;
        virtual void SetEnable(GraphicsEnum en) = 0;
        virtual void SetDisable(GraphicsEnum en) = 0;
        virtual void SetClearStencil(int s) = 0;
        virtual void SetColorMask(bool r, bool g, bool b, bool a) = 0;
        virtual void DispatchCompute(uint32_t x, uint32_t y, uint32_t z) = 0; 
    };

    template<GraphicsAPI type>
    class Drive : public IDrive
    {
    public:
        int  Load() override;
        int  Load(void*) override;
        void Viewport(int x, int y, int w, int h) override;
        void Clear(int type) override;
        void ClearColor(float r, float g, float b, float a) override;
        void SetLineWidth(float width) override;
        void DrawElements(ElemMode mode, int size, ElemType type, void* indices, size_t instanceCount = 1) override;
        void DrawArrays(ElemMode mode, int first, size_t count, size_t instanceCount = 1) override;
        void BufferData(int target, size_t size, const void * data, int usage) override;
        void BufferSubData(int target, signed long long int offset, size_t size, const void *data) override;
        void VertexAttribPointer(uint32_t index, int size, int type, bool normalized, int stride, const void *pointer) override;
        void EnableVertexAttribArray(uint32_t index) override;
        void SetPipeLineState(PipeLineState pso) override;
        void ReadPixels(int x, int y, int width, int height, ColorFormat format, ElemType type, void *pixels) override;
        void EnableByteAlignment(bool value) override;
        void EnableMultiSample(bool value) override;
        void SetPolygonMode(GraphicsFace face, GraphicsFaceMode mode) override;
        void SetStencilFunc(GraphicsEnum en, int ref, uint32_t mask) override;
        void SetStencilOp(GraphicsEnum sfail, GraphicsEnum dpfail, GraphicsEnum dppass) override;
        void SetStencilMask(uint32_t mask) override;
        void SetEnable(GraphicsEnum en) override;
        void SetDisable(GraphicsEnum en) override;
        void SetClearStencil(int s) override;
        void SetColorMask(bool r, bool g, bool b, bool a) override;
        void DispatchCompute(uint32_t x, uint32_t y, uint32_t z) override; 
    };

    using CurrentDrive = Drive<OpenGL>; 

} // namespace SEngine


#endif

